package com.tiny.tinyweb.core.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 访问类成员的反射工具类。
 *
 * @author wxiaobin
 * @version 1.0
 * @since 1.0
 */
public class ReflectionUtils {
    /**
     * 获得指定对象的指定属性的值，无论该属性是否可读。
     *
     * @param target 指定对象
     * @param name 指定属性名
     * @return 指定属性的值
     */
    public static Object getPropertyValue(Object target, String name) {
        // 目标对象未指定或字段名未指定时，直接返回空值
        if (target == null || name == null || name.isEmpty()) {
            return null;
        }

        try {
            Field field = target.getClass().getDeclaredField(name);
            // 暴力访问私有字段
            field.setAccessible(true);
            return field.get(target);
        } catch (Exception e) {
            // 访问失败时尝试通过Get方法访问
            try {
                return PropertyUtils.getProperty(target, name);
            } catch (Exception ex) {
                return null;
            }
        }
    }

    /**
     * @see {@link ReflectionUtils#findMethod(Class, String, String, String, Class, Class[], int)}
     */
    public static Method findMethod(Class<?> target, String name) {
        return findMethod(target, name, "", "", null, null, 0);
    }

    /**
     * @see {@link ReflectionUtils#findMethod(Class, String, String, String, Class, Class[], int)}
     */
    public static Method findMethod(Class<?> target, String name, String prefix, Class<?>[] parameterTypes) {
        return findMethod(target, name, prefix, "", null, parameterTypes, 0);
    }

    /**
     * @see {@link ReflectionUtils#findMethod(Class, String, String, String, Class, Class[], int)}
     */
    public static Method findMethod(Class<?> target, String name, Class<?>[] parameterTypes) {
        return findMethod(target, name, "", parameterTypes);
    }

    /**
     * @see {@link ReflectionUtils#findMethod(Class, String, String, String, Class, Class[], int)}
     */
    public static Method findMethod(Class<?> target, String name, String prefix, int parameterCount) {
        return findMethod(target, name, prefix, "", null, null, parameterCount);
    }

    /**
     * @see {@link ReflectionUtils#findMethod(Class, String, String, String, Class, Class[], int)}
     */
    public static Method findMethod(Class<?> target, String name, int parameterCount) {
        return findMethod(target, name, "", parameterCount);
    }

    /**
     * 从目标类中查找符合条件的方法。</br>
     * <ul>
     * <li>仅方法名：<code>findMethod(target, name, prefix, suffix, null, null, 0)</code></li>
     * <li>返回值类型：<code>findMethod(target, name, "", "", returnType, null, 0)</code></li>
     * <li>参数个数：<code>findMethod(target, name, "set", "", null, null, 1)</code></li>
     * <li>参数类型：<code>findMethod(target, name, "", "01", null, new Class[]{String.class}, 0)</code></li>
     * </ul>
     *
     * @param target 目标类
     * @param name 字段名
     * @param prefix 方法名前缀
     * @param suffix 方法名后缀
     * @param returnType 返回值类型
     * @param parameterTypes 参数类型
     * @param parameterCount 参数个数
     * @return 符合条件的{@link java.lang.reflect.Method}对象
     */
    public static Method findMethod(
            Class<?> target, String name, String prefix, String suffix,
            Class<?> returnType, Class<?>[] parameterTypes, int parameterCount) {
        // 目标类未指定或字段名未指定时，直接返回空值
        if (target == null || name == null || name.isEmpty()) {
            return null;
        }

        // 如果指定了方法名前缀和后缀，将它们和字段名组合成方法名
        StringBuilder fieldName = new StringBuilder();
        if (prefix != null && !prefix.isEmpty()) {
            fieldName.append(prefix);
        }
        fieldName.append(StringUtils.capitalize(name));
        if (suffix != null && !suffix.isEmpty()) {
            fieldName.append(StringUtils.capitalize(suffix));
        }

        // 查找符合条件的方法
        try {
            // 处理接口或类的所有方法
            Method[] methods = target.isInterface() ? target.getMethods() : target.getDeclaredMethods();
            for (Method method : methods) {
                // 条件：方法名、返回值类型、参数个数或参数类型
                if (method.getName().equals(fieldName.toString())
                        && (returnType == null || returnType == method.getReturnType())
                        && ((parameterTypes == null && (method.getParameterTypes() == null
                        || parameterCount == method.getParameterTypes().length))
                        || Arrays.equals(parameterTypes, method.getParameterTypes()))) {
                    return method;
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
}
